import { App, Plugin } from "obsidian";

/**
 * 通用持久化存储工具类
 * 支持插件级别的数据持久化，可以保存任意类型的数据
 */
export class StorageUtil {
	private app: App;
	private plugin: Plugin;
	private cache: Map<string, any> = new Map();

	constructor(app: App, plugin: Plugin) {
		this.app = app;
		this.plugin = plugin;
	}

	/**
	 * 获取存储的数据
	 * @param key 存储键
	 * @param defaultValue 默认值
	 * @returns 存储的数据或默认值
	 */
	async getData<T>(key: string, defaultValue: T): Promise<T> {
		// 先从缓存中获取
		if (this.cache.has(key)) {
			return this.cache.get(key);
		}

		try {
			// 从插件数据中获取
			const data = await this.plugin.loadData();
			const value = data && data[key] !== undefined ? data[key] : defaultValue;

			// 缓存数据
			this.cache.set(key, value);
			return value;
		} catch (error) {
			console.error(`获取存储数据失败 [${key}]:`, error);
			this.cache.set(key, defaultValue);
			return defaultValue;
		}
	}

	/**
	 * 保存数据到存储
	 * @param key 存储键
	 * @param value 要保存的值
	 */
	async setData<T>(key: string, value: T): Promise<void> {
		try {
			// 更新缓存
			this.cache.set(key, value);

			// 获取现有数据
			const data = await this.plugin.loadData() || {};

			// 更新数据
			data[key] = value;

			// 保存到文件
			await this.plugin.saveData(data);
		} catch (error) {
			console.error(`保存存储数据失败 [${key}]:`, error);
			throw error;
		}
	}

	/**
	 * 删除存储的数据
	 * @param key 存储键
	 */
	async removeData(key: string): Promise<void> {
		try {
			// 从缓存中删除
			this.cache.delete(key);

			// 获取现有数据
			const data = await this.plugin.loadData() || {};

			// 删除数据
			delete data[key];

			// 保存到文件
			await this.plugin.saveData(data);
		} catch (error) {
			console.error(`删除存储数据失败 [${key}]:`, error);
			throw error;
		}
	}

	/**
	 * 检查是否存在指定的数据
	 * @param key 存储键
	 * @returns 是否存在
	 */
	async hasData(key: string): Promise<boolean> {
		try {
			const data = await this.plugin.loadData();
			return data && data[key] !== undefined;
		} catch (error) {
			console.error(`检查存储数据失败 [${key}]:`, error);
			return false;
		}
	}

	/**
	 * 获取所有存储的键
	 * @returns 所有键的数组
	 */
	async getAllKeys(): Promise<string[]> {
		try {
			const data = await this.plugin.loadData();
			return data ? Object.keys(data) : [];
		} catch (error) {
			console.error('获取所有存储键失败:', error);
			return [];
		}
	}

	/**
	 * 清空所有存储数据
	 */
	async clearAll(): Promise<void> {
		try {
			this.cache.clear();
			await this.plugin.saveData({});
		} catch (error) {
			console.error('清空存储数据失败:', error);
			throw error;
		}
	}

	/**
	 * 批量获取数据
	 * @param keys 键数组
	 * @returns 键值对象
	 */
	async getBatchData<T>(keys: string[]): Promise<Record<string, T>> {
		try {
			const data = await this.plugin.loadData() || {};
			const result: Record<string, T> = {};

			for (const key of keys) {
				if (this.cache.has(key)) {
					result[key] = this.cache.get(key);
				} else if (data[key] !== undefined) {
					result[key] = data[key];
					this.cache.set(key, data[key]);
				}
			}

			return result;
		} catch (error) {
			console.error('批量获取存储数据失败:', error);
			return {};
		}
	}

	/**
	 * 批量保存数据
	 * @param dataMap 键值对象
	 */
	async setBatchData<T>(dataMap: Record<string, T>): Promise<void> {
		try {
			// 获取现有数据
			const data = await this.plugin.loadData() || {};

			// 更新数据和缓存
			for (const [key, value] of Object.entries(dataMap)) {
				data[key] = value;
				this.cache.set(key, value);
			}

			// 保存到文件
			await this.plugin.saveData(data);
		} catch (error) {
			console.error('批量保存存储数据失败:', error);
			throw error;
		}
	}

	/**
	 * 获取数组类型数据并提供数组操作方法
	 * @param key 存储键
	 * @param defaultValue 默认数组值
	 * @returns 数组操作对象
	 */
	getArrayData<T>(key: string, defaultValue: T[] = []): ArrayStorageHelper<T> {
		return new ArrayStorageHelper<T>(this, key, defaultValue);
	}

	/**
	 * 获取对象类型数据并提供对象操作方法
	 * @param key 存储键
	 * @param defaultValue 默认对象值
	 * @returns 对象操作对象
	 */
	getObjectData<T extends Record<string, any>>(key: string, defaultValue: T = {} as T): ObjectStorageHelper<T> {
		return new ObjectStorageHelper<T>(this, key, defaultValue);
	}
}

/**
 * 数组存储辅助类
 * 提供对数组类型存储数据的便捷操作方法
 */
export class ArrayStorageHelper<T> {
	private storage: StorageUtil;
	private key: string;
	private defaultValue: T[];

	constructor(storage: StorageUtil, key: string, defaultValue: T[]) {
		this.storage = storage;
		this.key = key;
		this.defaultValue = defaultValue;
	}

	/**
	 * 获取数组数据
	 */
	async get(): Promise<T[]> {
		return await this.storage.getData(this.key, this.defaultValue);
	}

	/**
	 * 设置数组数据
	 */
	async set(value: T[]): Promise<void> {
		await this.storage.setData(this.key, value);
	}

	/**
	 * 添加元素到数组末尾
	 */
	async push(item: T): Promise<void> {
		const array = await this.get();
		array.push(item);
		await this.set(array);
	}

	/**
	 * 添加元素到数组开头
	 */
	async unshift(item: T): Promise<void> {
		const array = await this.get();
		array.unshift(item);
		await this.set(array);
	}

	/**
	 * 删除并返回数组末尾元素
	 */
	async pop(): Promise<T | undefined> {
		const array = await this.get();
		const item = array.pop();
		await this.set(array);
		return item;
	}

	/**
	 * 删除并返回数组开头元素
	 */
	async shift(): Promise<T | undefined> {
		const array = await this.get();
		const item = array.shift();
		await this.set(array);
		return item;
	}

	/**
	 * 删除指定索引的元素
	 */
	async removeAt(index: number): Promise<T[]> {
		const array = await this.get();
		array.splice(index, 1);
		await this.set(array);
		return array;
	}

	/**
	 * 删除匹配的元素
	 */
	async remove(predicate: (item: T) => boolean): Promise<T[]> {
		const array = await this.get();
		const newArray = array.filter(item => !predicate(item));
		await this.set(newArray);
		return newArray;
	}

	/**
	 * 在指定位置插入元素
	 */
	async insert(index: number, item: T): Promise<void> {
		const array = await this.get();
		array.splice(index, 0, item);
		await this.set(array);
	}

	/**
	 * 查找元素索引
	 */
	async indexOf(predicate: (item: T) => boolean): Promise<number> {
		const array = await this.get();
		return array.findIndex(predicate);
	}

	/**
	 * 获取数组长度
	 */
	async length(): Promise<number> {
		const array = await this.get();
		return array.length;
	}

	/**
	 * 清空数组
	 */
	async clear(): Promise<void> {
		await this.set([]);
	}

	/**
	 * 限制数组长度
	 */
	async limitLength(maxLength: number): Promise<T[]> {
		const array = await this.get();
		if (array.length > maxLength) {
			const newArray = array.slice(0, maxLength);
			await this.set(newArray);
			return newArray;
		}
		return array;
	}
}

/**
 * 对象存储辅助类
 * 提供对对象类型存储数据的便捷操作方法
 */
export class ObjectStorageHelper<T extends Record<string, any>> {
	private storage: StorageUtil;
	private key: string;
	private defaultValue: T;

	constructor(storage: StorageUtil, key: string, defaultValue: T) {
		this.storage = storage;
		this.key = key;
		this.defaultValue = defaultValue;
	}

	/**
	 * 获取对象数据
	 */
	async get(): Promise<T> {
		return await this.storage.getData(this.key, this.defaultValue);
	}

	/**
	 * 设置对象数据
	 */
	async set(value: T): Promise<void> {
		await this.storage.setData(this.key, value);
	}

	/**
	 * 获取对象属性值
	 */
	async getProperty<K extends keyof T>(property: K): Promise<T[K]> {
		const obj = await this.get();
		return obj[property];
	}

	/**
	 * 设置对象属性值
	 */
	async setProperty<K extends keyof T>(property: K, value: T[K]): Promise<void> {
		const obj = await this.get();
		obj[property] = value;
		await this.set(obj);
	}

	/**
	 * 删除对象属性
	 */
	async removeProperty<K extends keyof T>(property: K): Promise<void> {
		const obj = await this.get();
		delete obj[property];
		await this.set(obj);
	}

	/**
	 * 检查是否存在指定属性
	 */
	async hasProperty<K extends keyof T>(property: K): Promise<boolean> {
		const obj = await this.get();
		return property in obj;
	}

	/**
	 * 获取所有属性键
	 */
	async getKeys(): Promise<string[]> {
		const obj = await this.get();
		return Object.keys(obj);
	}

	/**
	 * 合并对象
	 */
	async merge(updateObj: Partial<T>): Promise<void> {
		const obj = await this.get();
		const merged = { ...obj, ...updateObj };
		await this.set(merged);
	}

	/**
	 * 清空对象
	 */
	async clear(): Promise<void> {
		await this.set({} as T);
	}
}
